<?php
namespace app\common\traits;

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\ValidationData;
use \think\facade\Config;

trait JWT
{
    private $signKey; // 签名KEY
    private $issuer; // 签发者
    private $expiresAt; // 持续时间，单位秒
    
    // 从配置文件获取参数
    protected function setKeyData() {
        $this->signKey   = Config::get('custom.jwt_sign_key');
        $this->issuer    = Config::get('custom.jwt_issuer');
        $this->expiresAt = Config::get('custom.jwt_expires_time');
    }
    
    /**
     * 生成json web token 字符串
     * @param int $userId 用户id
     * @return string $token
     */
    protected function generateJWT($userId){
        
        $this->setKeyData();
        
        $signer = new Sha256();
        $time = time();
        
        $token = (new Builder())->issuedBy($this->issuer)
                ->issuedAt($time)
                ->canOnlyBeUsedAfter($time)
                ->expiresAt($time + $this->expiresAt)
                ->withClaim('user_id', $userId)
                ->getToken($signer, new Key($this->signKey));
        
        return (string)$token;
    }
    
    /**
     * 将jwt字符串解析成Token对象
     * @param $token
     * @return \Lcobucci\JWT\Token
     */
    protected function parseJWT($token)
    {
        return (new Parser())->parse((string) $token); // Parses from a string
    }
    
    /**
     * 验证token正确和有效
     * @param string $token token字符串aaa.bbb.ccc
     * @return bool
     */
    protected function checkJWT($token){
        $verifyFlag = $this->verifyJWT($token);
        $validateFlag = $this->validateJWT($token);
        
        return ( $verifyFlag && $validateFlag );
    }
    
    /**
     * 验证token正确，签名是否正确
     * @param string $token token字符串aaa.bbb.ccc
     * @return bool
     */
    protected function verifyJWT($token)
    {
        $this->setKeyData();
        
        $tokenObj = $this->parseJWT($token);
        $signer = new Sha256();
        return $tokenObj->verify($signer, $this->signKey);
    }
    
    /**
     * 验证token有效，是否过期
     * @param string $token token字符串aaa.bbb.ccc
     * @return bool
     */
    protected function validateJWT($token){
        
        $this->setKeyData();
        
        $tokenObj = $this->parseJWT($token);
        
        $data = new ValidationData(); 
        
        $data->setIssuer($this->issuer);
        
        return $tokenObj->validate($data); 
    }
    
    /**
     * 从jwt字符串中获取用户ID
     * @param string $token
     * @return mixed
     */
    protected function getUserIdFromJWT($token)
    {
        $tokenObj = $this->parseJWT($token);
        return $tokenObj->getClaim('user_id');
    }
}